package com.wink_172.library.utils

import android.content.res.AssetManager
import android.app.Activity
import android.content.Intent
import android.widget.Toast
import android.os.Environment
import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import android.provider.MediaStore
import android.os.StatFs
import android.text.TextUtils
import android.util.Log
import org.xutils.x
import java.io.*
import java.lang.Exception
import java.lang.IllegalArgumentException
import java.lang.StringBuilder
import java.nio.charset.Charset
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import kotlin.Throws

class FileUtil {
    enum class FileType {
        IMG, AUDIO, VIDEO, FILE
    }

    private fun getAssert(context: Context): InputStream? {
        var `is`: InputStream? = null
        try {
            val assetManager = context.assets
            //            AssetFileDescriptor fileDescriptor = assetManager.openFd("chengdu.mp3");
            `is` = assetManager.open(String.format("emoticon/%d.gif", 22))
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return `is`
    }

    companion object {
        private fun openFile(activity: Activity, file: File) {
            val intent = Intent()
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            intent.action = Intent.ACTION_VIEW
            val type = getMIMEType(file)
            intent.setDataAndType(Uri.fromFile(file), type)
            try {
                activity.startActivity(intent)
            } catch (e: Exception) {
                Toast.makeText(activity, "未知类型，不能打开", Toast.LENGTH_SHORT).show()
            }
        }

        private fun getMIMEType(file: File): String {
            var type = "*/*"
            val fileName = file.name
            val dotIndex = fileName.indexOf('.')
            if (dotIndex < 0) {
                return type
            }
            val end = fileName.substring(dotIndex, fileName.length)
                .toLowerCase()
            if (end === "") {
                return type
            }
            for (i in MIME_MapTable.indices) {
                if (end === MIME_MapTable[i][0]) {
                    type = MIME_MapTable[i][1]
                }
            }
            return type
        }

        private val MIME_MapTable = arrayOf(
            arrayOf(".3gp", "video/3gpp"),
            arrayOf(".apk", "application/vnd.android.package-archive"),
            arrayOf(".asf", "video/x-ms-asf"),
            arrayOf(".avi", "video/x-msvideo"),
            arrayOf(".bin", "application/octet-stream"),
            arrayOf(".bmp", "image/bmp"),
            arrayOf(".c", "text/plain"),
            arrayOf(".class", "application/octet-stream"),
            arrayOf(".conf", "text/plain"),
            arrayOf(".cpp", "text/plain"),
            arrayOf(".doc", "application/msword"),
            arrayOf(
                ".docx",
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
            ),
            arrayOf(".xls", "application/vnd.ms-excel"),
            arrayOf(
                ".xlsx",
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
            ),
            arrayOf(".exe", "application/octet-stream"),
            arrayOf(".gif", "image/gif"),
            arrayOf(".gtar", "application/x-gtar"),
            arrayOf(".gz", "application/x-gzip"),
            arrayOf(".h", "text/plain"),
            arrayOf(".htm", "text/html"),
            arrayOf(".html", "text/html"),
            arrayOf(".jar", "application/java-archive"),
            arrayOf(".java", "text/plain"),
            arrayOf(".jpeg", "image/jpeg"),
            arrayOf(".jpg", "image/jpeg"),
            arrayOf(".js", "application/x-javascript"),
            arrayOf(".log", "text/plain"),
            arrayOf(".m3u", "audio/x-mpegurl"),
            arrayOf(".m4a", "audio/mp4a-latm"),
            arrayOf(".m4b", "audio/mp4a-latm"),
            arrayOf(".m4p", "audio/mp4a-latm"),
            arrayOf(".m4u", "video/vnd.mpegurl"),
            arrayOf(".m4v", "video/x-m4v"),
            arrayOf(".mov", "video/quicktime"),
            arrayOf(".mp2", "audio/x-mpeg"),
            arrayOf(".mp3", "audio/x-mpeg"),
            arrayOf(".mp4", "video/mp4"),
            arrayOf(".mpc", "application/vnd.mpohun.certificate"),
            arrayOf(".mpe", "video/mpeg"),
            arrayOf(".mpeg", "video/mpeg"),
            arrayOf(".mpg", "video/mpeg"),
            arrayOf(".mpg4", "video/mp4"),
            arrayOf(".mpga", "audio/mpeg"),
            arrayOf(".msg", "application/vnd.ms-outlook"),
            arrayOf(".ogg", "audio/ogg"),
            arrayOf(".pdf", "application/pdf"),
            arrayOf(".png", "image/png"),
            arrayOf(".pps", "application/vnd.ms-powerpoint"),
            arrayOf(".ppt", "application/vnd.ms-powerpoint"),
            arrayOf(
                ".pptx",
                "application/vnd.openxmlformats-officedocument.presentationml.presentation"
            ),
            arrayOf(".prop", "text/plain"),
            arrayOf(".rc", "text/plain"),
            arrayOf(".rmvb", "audio/x-pn-realaudio"),
            arrayOf(".rtf", "application/rtf"),
            arrayOf(".sh", "text/plain"),
            arrayOf(".tar", "application/x-tar"),
            arrayOf(".tgz", "application/x-compressed"),
            arrayOf(".txt", "text/plain"),
            arrayOf(".wav", "audio/x-wav"),
            arrayOf(".wma", "audio/x-ms-wma"),
            arrayOf(".wmv", "audio/x-ms-wmv"),
            arrayOf(".wps", "application/vnd.ms-works"),
            arrayOf(".xml", "text/plain"),
            arrayOf(".z", "application/x-compress"),
            arrayOf(".zip", "application/x-zip-compressed"),
            arrayOf("", "*/*")
        )
        val EXTERNAL_DATA_DIR = "/Android/data/" + x.app().packageName + "/files/"
        val isExternalStorageMounted: Boolean
            get() = Environment.MEDIA_MOUNTED ==
                    Environment.getExternalStorageState()
        val externalStorageDir: File
            get() = Environment.getExternalStorageDirectory()
        val appExternalDataDir: File?
            get() {
                if (isExternalStorageMounted) {
                    val appDir = File(externalStorageDir, EXTERNAL_DATA_DIR)
                    if (!appDir.exists()) {
                        synchronized(appDir) {
                            if (!appDir.exists()) {
                                appDir.mkdirs()
                            }
                        }
                    }
                    return appDir
                }
                return null
            }

        /**
         * @param type the files type.
         */
        fun getAppFilesDir(type: String?): File? {
            if (!isExternalStorageMounted) {
                return null
            }
            if (type == null || type.trim { it <= ' ' } == "") {
                return appExternalDataDir
            }
            val typeDir = File(appExternalDataDir, type)
            if (!typeDir.exists()) {
                synchronized(typeDir) {
                    if (!typeDir.exists()) {
                        typeDir.mkdirs()
                    }
                }
            }
            return typeDir
        }

        fun makeRootDirectory(filePath: String?) {
            var file: File? = null
            try {
                file = File(filePath)
                if (!file.exists()) {
                    file.mkdir()
                }
            } catch (e: Exception) {
                Log.i("error:", e.toString() + "")
            }
        }

        //    通过Uri获取路径以及文件名一种方法
        fun getRealFilePath(context: Context, uri: Uri): String {

            val scheme = uri.scheme
            var data: String = ""
            if (scheme == null) {data = uri.path!!}
            else if (ContentResolver.SCHEME_FILE == scheme) {
                data = uri.path!!
            } else if (ContentResolver.SCHEME_CONTENT == scheme) {
                val cursor = context.contentResolver.query(
                    uri,
                    arrayOf(MediaStore.Images.ImageColumns.DATA),
                    null,
                    null,
                    null
                )
                if (null != cursor) {
                    if (cursor.moveToFirst()) {
                        val index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA)
                        if (index > -1) {
                            data = cursor.getString(index)
                        }
                    }
                    cursor.close()
                }
            }
            return data
        }

        /**
         * 检查SD卡是否存在
         */
        fun checkSdCard(): Boolean {
            return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
        }

        /**
         * 获取手机SD卡总空间
         */
        val sDcardTotalSize: Long
            get() = if (checkSdCard()) {
                val path = Environment.getExternalStorageDirectory()
                val mStatFs = StatFs(path.path)
                val blockSizeLong = mStatFs.blockSizeLong
                val blockCountLong = mStatFs.blockCountLong
                blockSizeLong * blockCountLong
            } else {
                0
            }

        /**
         * 获取SDka可用空间
         */
        val sDcardAvailableSize: Long
            get() = if (checkSdCard()) {
                val path = Environment.getExternalStorageDirectory()
                val mStatFs = StatFs(path.path)
                val blockSizeLong = mStatFs.blockSizeLong
                val availableBlocksLong = mStatFs.availableBlocksLong
                blockSizeLong * availableBlocksLong
            } else {
                0
            }

        /**
         * 获取手机内部存储总空间
         */
        val phoneTotalSize: Long
            get() = if (!checkSdCard()) {
                val path = Environment.getDataDirectory()
                val mStatFs = StatFs(path.path)
                val blockSizeLong = mStatFs.blockSizeLong
                val blockCountLong = mStatFs.blockCountLong
                blockSizeLong * blockCountLong
            } else {
                sDcardTotalSize
            }

        /**
         * 获取手机内存存储可用空间
         */
        val phoneAvailableSize: Long
            get() = if (!checkSdCard()) {
                val path = Environment.getDataDirectory()
                val mStatFs = StatFs(path.path)
                val blockSizeLong = mStatFs.blockSizeLong
                val availableBlocksLong = mStatFs.availableBlocksLong
                blockSizeLong * availableBlocksLong
            } else sDcardAvailableSize

        /**
         * Java文件操作 获取文件扩展名
         *
         * 输入/storage/emulated/0/天天跳舞/dynamic_high_8XZ31671160284179.jpg
         * 输出jpg
         */
        fun getExtensionName(filename: String?): String? {
            if (filename != null && filename.length > 0) {
                val dot = filename.lastIndexOf('.')
                if (dot > -1 && dot < filename.length - 1) {
                    return filename.substring(dot + 1)
                }
            }
            return filename
        }

        /**
         * 获取文件名及后缀
         * 不建议使用  因为会有中文的文件
         * 输入/storage/emulated/0/天天跳舞/dynamic_high_8XZ31671160284179.jpg
         * 输出dynamic_high_8XZ31671160284179.jpg
         */
        fun getFileNameWithSuffix(path: String): String {
            if (TextUtils.isEmpty(path)) {
                return ""
            }
            val start = path.lastIndexOf("/")
            return if (start != -1) {
                path.substring(start + 1)
            } else {
                ""
            }
        }

        /**
         * 输入/storage/emulated/0/天天跳舞/dynamic_high_8XZ31671160284179.jpg
         * 输出 .jpg
         */
        fun getFileEx(filename: String): String{
            if (filename != null && filename.length > 0) {
                val dot = filename.lastIndexOf('.')
                if (dot > -1 && dot < filename.length) {
                    return filename.substring(dot, filename.length)
                }
            }
            return filename
        }
        /**
         * 输入/storage/emulated/0/天天跳舞/dynamic_high_8XZ31671160284179.jpg
         * 输出/storage/emulated/0/天天跳舞/dynamic_high_8XZ31671160284179
         */
        fun getFileNameNoEx(filename: String?): String? {
            if (filename != null && filename.length > 0) {
                val dot = filename.lastIndexOf('.')
                if (dot > -1 && dot < filename.length) {
                    return filename.substring(0, dot)
                }
            }
            return filename
        }

        /**
         * 获取网络链接的文件名
         * pathandname   http://106.52.115.24:8080/download/xiaxuanpin.apk
         * 得到  /xiaxuanpin.apk
         *
         * 输入/storage/emulated/0/天天跳舞/dynamic_high_8XZ31671160284179.jpg
         * 输出/dynamic_high_8XZ31671160284179.jpg
         */
        fun getFileUrlName(pathandname: String): String? {
            val start = pathandname.lastIndexOf("/")
            return if (start != -1) {
                pathandname.substring(start)
            } else {
                null
            }
        }

        /**
         * 输入/storage/emulated/0/天天跳舞/dynamic_high_8XZ31671160284179.jpg
         * 输出dynamic_high_8XZ31671160284179.jpg
         */
        fun getFileName(filePath: String?): String? {
            val file = File(filePath)
            return if (file.exists() && !file.isDirectory && file.canRead()) file.name else null
        }

        fun isLegalFile(filePath: String?): Boolean {
            val file = File(filePath)
            return file.exists() && !file.isDirectory && file.canRead()
        }

        /**
         * 文件大小
         */
        @Throws(Exception::class)
        fun getFileLength(filePath: String?): Long {
            return if (!isLegalFile(filePath)) {
                throw IllegalArgumentException("文件不存在、或不可读、或者是一个目录")
            } else {
                val file = File(filePath)
                file.length()
            }
        }

        @Throws(Exception::class)
        fun getFileInputStream(filePath: String?): FileInputStream {
            return FileInputStream(filePath)
        }

        fun closeFileStream(inputStream: InputStream?) {
            try {
                inputStream?.close()
            } catch (var2: IOException) {
                var2.printStackTrace()
            }
        }

        @Throws(Exception::class)
        fun getFileContent(filePath: String?): String? {
            val fileLength = java.lang.Long.valueOf(getFileLength(filePath)).toInt()
            return getFileContent(filePath, 0L, fileLength)
        }

        @Throws(Exception::class)
        fun getFileContent(filePath: String?, offset: Long, length: Int): String? {
            var fileInputStream: FileInputStream? = null
            val var5: String?
            try {
                fileInputStream = getFileInputStream(filePath)
                var5 = getFileContent(fileInputStream as InputStream?, offset, length)
            } finally {
                closeFileStream(fileInputStream)
            }
            return var5
        }

        @Throws(Exception::class)
        fun getFileContent(inputStream: InputStream?, offset: Long, length: Int): String? {
            val fileContent = getFileContentByte(inputStream, offset, length)
            return if (fileContent == null) null else String(
                fileContent,
                Charset.forName("ISO-8859-1")
            )
        }

        @Throws(Exception::class)
        fun getFileContentByte(inputStream: InputStream?, offset: Long, length: Int): ByteArray {
            return if (offset >= 0L && length >= 0) {
                val tempBuf = ByteArray(length)
                inputStream!!.skip(offset)
                val readLen = inputStream.read(tempBuf)
                val fileContent: ByteArray
                if (readLen < 0) {
                    fileContent = ByteArray(0)
                    fileContent
                } else {
                    if (readLen < length) {
                        fileContent = ByteArray(readLen)
                        System.arraycopy(tempBuf, 0, fileContent, 0, readLen)
                    } else {
                        fileContent = tempBuf
                    }
                    fileContent
                }
            } else {
                throw Exception("getFileContent param error")
            }
        }

        fun delete(filePath: String?) {
            val file = File(filePath)
            if (file.exists() && file.isFile) {
                file.delete()
            }
        }

        private const val TAG = "TAG"

        /**
         * 判断文件是否存在
         * file.exists()，明明文件存在，10秒内都返回flase，10秒后返回true
         * 最后在代码前加一句解决 System.currentTimeMillis();
         */
        fun isCacheFileExist(absoFilePath: String?): Boolean {
            System.currentTimeMillis()
            val file = File(absoFilePath)
            return file.exists()
        }

        /**
         * get content from a raw resource. This can only be used with resources whose value is the name of an asset files
         * -- that is, it can be used to open drawable, sound, and raw resources; it will fail on string and color
         * resources.
         *
         * @param context
         * @param resId   The resource identifier to open, as generated by the appt tool.
         * @return
         */
        fun geFileFromRaw(context: Context?, resId: Int): String? {
            if (context == null) {
                return null
            }
            val s = StringBuilder()
            return try {
                val `in` = InputStreamReader(context.resources.openRawResource(resId))
                val br = BufferedReader(`in`)
                var line: String?
                while (br.readLine().also { line = it } != null) {
                    s.append(line)
                }
                s.toString()
            } catch (e: IOException) {
                e.printStackTrace()
                null
            }
        }

        /**
         * 创建文件
         */
        fun createFile(path: String?): Boolean {
            val dir = File(path)
            var result = true
            if (!dir.exists()) {
                try {
                    result = dir.createNewFile()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
            return result
        }

        /**
         * 创建文件夹
         */
        fun createFolder(path: String?) {
            val dir = File(path)
            if (!dir.isDirectory) {
                dir.mkdirs()
            }
        }

        val isExternalStorageWritable: Boolean
            get() {
                val state = Environment.getExternalStorageState()
                return if (Environment.MEDIA_MOUNTED == state) {
                    true
                } else false
            }

        fun copyDirectory(source: String?, destine: String?): Boolean {
            if (source == null || destine == null) {
                return false
            }
            val dirSource = File(source)
            if (!dirSource.isDirectory) {
                return false
            }
            val dirDestine = File(destine)
            if (!dirDestine.exists()) {
                dirDestine.mkdirs()
            }
            val childList = dirSource.list()
            if (childList != null && childList.size > 0) {
                for (fileName in childList) {
                    val childSource = source + File.separator + fileName
                    val childDestine = destine + File.separator + fileName
                    val childSourceFile = File(childSource)
                    if (childSourceFile.isFile) {
                        copyFile(childSource, childDestine)
                    } else {
                        copyDirectory(childSource, childDestine)
                    }
                }
            }
            return true
        }

        fun copyFile(source: String?, destine: String?): Boolean {
            if (source == null || destine == null) {
                return false
            }
            val fileSource = File(source)
            if (!fileSource.exists()) {
                return false
            }
            val fileDestine = File(destine)
            if (fileDestine.exists()) {
                return false
            }
            var result = false
            var fis: FileInputStream? = null
            var fos: FileOutputStream? = null
            try {
                var readSize = 0
                val buffer = ByteArray(1024)
                fileDestine.createNewFile()
                fis = FileInputStream(fileSource)
                fos = FileOutputStream(fileDestine)
                while (fis.read(buffer).also { readSize = it } != -1) {
                    fos.write(buffer, 0, readSize)
                }
                result = true
            } catch (e: Exception) {
                e.printStackTrace()
            } finally {
                if (fos != null) {
                    try {
                        fos.close()
                    } catch (e: IOException) {
                    }
                }
                if (fis != null) {
                    try {
                        fis.close()
                    } catch (e: IOException) {
                    }
                }
            }
            return result
        }

        fun unzipFile(source: String?, destine: String?): Boolean {
            var destine = destine
            if (source == null || destine == null) {
                return false
            }
            var buffer: ByteArray? = null
            var result = false
            var fis: FileInputStream? = null
            var zis: ZipInputStream? = null
            try {
                if (!destine.endsWith(File.separator)) {
                    destine += File.separator
                }
                fis = FileInputStream(File(source))
                zis = ZipInputStream(fis)
                var zipEntry: ZipEntry
                while (zis.nextEntry.also { zipEntry = it } != null) {
                    val entryName = zipEntry.name
                    if (zipEntry.isDirectory) {
                        val file = File(destine + entryName)
                        file.mkdirs()
                    } else {
                        if (buffer == null) {
                            buffer = ByteArray(1024)
                        }
                        val file = File(destine + entryName)
                        file.createNewFile()
                        val fos = FileOutputStream(file)
                        var sizeRemains = zipEntry.size.toInt()
                        while (sizeRemains > 0) {
                            var sizeToRead = sizeRemains
                            if (sizeToRead > buffer.size) {
                                sizeToRead = buffer.size
                            }
                            val sizeRealRead = zis.read(buffer, 0, sizeToRead)
                            if (sizeRealRead > 0) {
                                fos.write(buffer, 0, sizeRealRead)
                                sizeRemains -= sizeRealRead
                            }
                        }
                        fos.close()
                    }
                    zis.closeEntry()
                }
                result = true
            } catch (e: Exception) {
                e.printStackTrace()
            } finally {
                if (zis != null) {
                    try {
                        zis.close()
                    } catch (ioe: IOException) {
                    }
                }
                if (fis != null) {
                    try {
                        fis.close()
                    } catch (ioe: IOException) {
                    }
                }
            }
            return result
        }
    }
}